package com.world.rickcloudendpoint.common.utils;

import lombok.extern.log4j.Log4j2;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @description: 提供对{@link ExecutorService}的工具类
 * @author: jlsong
 * @date: 2021/12/23 22:21:41
 * @version: 1.0
 */
@Log4j2
public final class ExecutorUtil {

    /**
     * 默认的{@link ExecutorService}关闭前等待其中的任务结束的时间:5分钟
     */
    private static final int DEFAULT_AWAIT_TERMINATE_MINUTES = 5;

    private ExecutorUtil() {
    }

    /**
     * 关闭{@link ExecutorService},在关闭之前最多等待
     * {@link #DEFAULT_AWAIT_TERMINATE_MINUTES}分钟来满足其中已经开始任务结束
     *
     * @param executorService
     * @return 返回停止后仍然为被开始执行的任务
     * @see {@link #shutdownAndAwaitTermination(ExecutorService, long, TimeUnit)}
     */
    public static List<Runnable> shutdownAndAwaitTermination(final ExecutorService executorService) {
        return shutdownAndAwaitTermination(executorService, DEFAULT_AWAIT_TERMINATE_MINUTES, TimeUnit.MINUTES);
    }

    /**
     * 关闭{@link ExecutorService},在指定的时间内{@code awaitTermateTimeout}等待
     * {@code executorService}中已经开始的任务尽量结束. 此实现参照{@link ExecutorService}
     * 注释中的 {@code shutdownAndAwaitTermination}策略
     *
     * @param executorService       将要被停止的{@link ExecutorService}
     * @param awaitTerminateTimeout 等待时间
     * @param timeUnit              awaitTerminate的单位
     * @return 返回停止后任然未被开始执行的任务
     */
    public static List<Runnable> shutdownAndAwaitTermination(final ExecutorService executorService,
                                                             final long awaitTerminateTimeout, final TimeUnit timeUnit) {
        List<Runnable> _left = null;
        executorService.shutdown();
        try {
            boolean _terminateResult = executorService.awaitTermination(awaitTerminateTimeout, timeUnit);

            log.info("[Shutdown " + executorService + ' '
                    + (_terminateResult ? "Success" : "Fail") + ']');

            if (!_terminateResult) {
                //再次停止
                _left = executorService.shutdownNow();
                if (_left != null) {
                    for (Runnable _o : _left) {
                        log.warn("Left runnable :" + _o);
                    }
                }
                _terminateResult = executorService.awaitTermination(awaitTerminateTimeout, timeUnit);
                log.info("[#GS.ExecutorUtil.shutdownAndAwaitTermination] [ShutdwonNow " + executorService + ' '
                        + (_terminateResult ? "Success" : "Fail") + ']');
            }
        } catch (InterruptedException e) {

            log.error("Shut down executor service failed,the reason is {} ", e.getMessage(), e);

            _left = executorService.shutdownNow();
            Thread.currentThread().interrupt();
        }
        return _left;
    }
}
